﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using fastJSON;
using gtasks.Auth;
using gtasks.Model;
using gtasks.Utils;
using pub.NET20Fix;

namespace gtasks
{
    internal class TaskListManager
    {
        public static TaskListManager Instance = new TaskListManager();
        private static readonly string url = "https://www.googleapis.com/tasks/v1/users/@me/lists";

        private Action<TaskLists> _callback;

        private WebRequest _request;

        public event Action<Exception> OnException;

        public void List(Action<TaskLists> callback)
        {
            _callback = callback;
            AuthManager.Instance.AuthExecute(() => {
                var req = HttpUtils.CreateRequest(url);
                SetRequest(req);
                return req;
            },
                req => req.BeginGetResponse(GetResponseCallback, req));
        }

        private void GetResponseCallback(IAsyncResult ar)
        {
            var req = ar.AsyncState as HttpWebRequest;
            WebResponse rsp;

            try
            {
//                throw new Exception("OOOPS");
                rsp = req.EndGetResponse(ar);
            }
            catch (Exception e)
            {
                AsyncUtils.FireOnException(OnException, e);
                return;
            }
            string text;
            using (var reader = new StreamReader(rsp.GetResponseStream()))
            {
                text = reader.ReadToEnd();
            }
            rsp.Close();
            try
            {
                var taskLists = JSON.Instance.ToObject<TaskLists>(text);
                Dispatcher.Current.Invoke(() => _callback(taskLists));
            }
            catch (Exception e)
            {
                AsyncUtils.FireOnException(OnException, e);
            }

//            Thread.Sleep(9000);
        }

        public void New(string title, Action<TaskList> callback)
        {
            AuthManager.Instance.AuthExecute(() => {
                var req = HttpUtils.CreateRequest(url);
                req.Method = "POST";
                req.ContentType = "application/json";
                SetRequest(req);
                var paramMap = new Dictionary<string, object> {{"title", title}};
                var json = JSON.Instance.ToJSON(paramMap);
                req.BeginGetRequestStream(ar => {
                    using (var sw = new StreamWriter(req.EndGetRequestStream(ar)))
                    {
                        sw.Write(json);
                        sw.Flush();
                        sw.Close();
                    }
                }, req);
                return req;
            }, req => req.BeginGetResponse(ar => {
                WebResponse rsp;

                try
                {
                    rsp = req.EndGetResponse(ar);
                }
                catch (Exception e)
                {
                    AsyncUtils.FireOnException(OnException, e);
                    return;
                }
                string text;
                using (var reader = new StreamReader(rsp.GetResponseStream()))
                {
                    text = reader.ReadToEnd();
                }
                rsp.Close();
                var taskList = JSON.Instance.ToObject<TaskList>(text);
                Dispatcher.Current.Invoke(() => callback(taskList));
            }, req));
        }

        public void Delete(string id, Action callback)
        {
            AuthManager.Instance.AuthExecute(() => {
                var req = HttpUtils.CreateRequest(url + "/" + id);
                req.Method = "DELETE";
                SetRequest(req);
                return req;
            }, req => req.BeginGetResponse(ar => {
                try
                {
                    var rsp = req.EndGetResponse(ar);
                    rsp.Close();
                }
                catch (Exception e)
                {
                    AsyncUtils.FireOnException(OnException, e);
                    return;
                }
                Dispatcher.Current.Invoke(callback);
            }, req));
        }

        private void SetRequest(WebRequest req)
        {
            try
            {
                if (_request != null)
                {
                    _request.Abort();
                }
            }
            catch
            {
                //ignore
            }
            _request = req;
        }

        public void AbortProcessing()
        {
            SetRequest(null);
            AuthManager.Instance.AbortProcessing();
        }

        public DateTime GetUpdateTime(string taskListId, string token)
        {
            var url = "https://www.googleapis.com/tasks/v1/users/@me/lists/" +
                taskListId + "?fields=updated";
            var req = HttpUtils.CreateRequest(url, token);
            var rsp = req.GetResponse();
            string text;
            using (var reader = new StreamReader(rsp.GetResponseStream()))
            {
                text = reader.ReadToEnd();
            }
            var updatedInfo = JSON.Instance.ToObject<UpdatedInfo>(text);
            rsp.Close();
            req.Abort();
            return updatedInfo.updated;
        }

        public void Get(string id, Action<TaskList> callback)
        {
            var url = "https://www.googleapis.com/tasks/v1/users/@me/lists/" + id;
            AuthManager.Instance.AuthExecute(() => {
                var req = HttpUtils.CreateRequest(url);
                SetRequest(req);
                return req;
            }, req => req.BeginGetResponse(ar => {
                HttpWebResponse rsp;
                try
                {
                    rsp = req.EndGetResponse(ar) as HttpWebResponse;
                }
                catch (Exception e)
                {
                    AsyncUtils.FireOnException(OnException, e);
                    return;
                }
                string text;
                using (var reader = new StreamReader(rsp.GetResponseStream()))
                {
                    text = reader.ReadToEnd();
                }
                rsp.Close();
                var taskList = JSON.Instance.ToObject<TaskList>(text);
                callback(taskList);
            }, req));
        }
    }
}